/**
 * Copyright ©2003~2019年8月9日 szkingdom
 * @author raohj
 * @date 2019年8月9日
 * @file RBase64.java
 * @comment : please input your comment to this file
 * @version : input version
 * @modify:
 * 		1、 2019年8月9日 由 raohj 新建文件
 */
package com.ccnu.crypt;

import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.*;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import java.util.zip.CRC32;

/**
 * @author raohj
 * @date 2019年8月9日
 * @version 
 * @comment to add your comment
 */
public class RCryptTest {
	// 编码、解码
	private static String msgText ="饶海军爱中国人1234";
	private static Logger log = LoggerFactory.getLogger(RCryptTest.class);
	
	public static void base64() {
		log.info("=================Begin Base64====================");
		// base64算法分为带url与不带url的版本。主要是+
		// 获取base加密工具类
		log.info("=================JDK Base64====================");
		Encoder enc = java.util.Base64.getEncoder();
		byte [] eccText = enc.encode(msgText.getBytes());
		log.info(new String(eccText));
		
		// 获取base解密工具类
		Decoder dec = java.util.Base64.getDecoder();
		log.info(new String(dec.decode(eccText)));
		
		// 编码Bouncy Castle
		log.info("=================Bouncy Castle====================");
		eccText = org.bouncycastle.util.encoders.Base64.encode(msgText.getBytes());
		log.info(new String(eccText));
		// 解码Bouncy Castle
		log.info(new String(org.bouncycastle.util.encoders.Base64.decode(eccText)));
		
		log.info("=================commons codecs	====================");
		eccText = org.apache.commons.codec.binary.Base64.encodeBase64(msgText.getBytes());
		log.info(new String(eccText));
		// 解码Bouncy Castle
		log.info(new String(org.apache.commons.codec.binary.Base64.decodeBase64(eccText)));		
	}
	
	private static void disgest(String algorithm) {
		// MD2
		try {
			MessageDigest md2 = MessageDigest.getInstance(algorithm);
			byte [] digt = md2.digest(msgText.getBytes());
			log.info( "[" + algorithm + "]"+ new String(Hex.encodeHex(digt)));			
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
	}
	
	public static void fileMd5() {
		String filePath = "D:/msdia80.dll";
		String algorithm = "MD5";
		log.info("=================Begin file md5====================");
		try {
			FileInputStream fis = new FileInputStream(new File(filePath));
			DigestInputStream dig = new DigestInputStream(fis, MessageDigest.getInstance(algorithm));
			int bufSize = 2048;
			byte [] buffer = new byte[bufSize];
			int read = dig.read(buffer, 0, bufSize);
			while(read > -1) {
				read = dig.read(buffer, 0, bufSize);
			}
			dig.close();
			MessageDigest md = dig.getMessageDigest();
			byte [] ecc = md.digest();
			log.info( "[File " + algorithm + "]"+ new String(Hex.encodeHex(ecc)));		
		} catch (IOException | NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
	}
	
	public static void md() {
		log.info("=================Begin md====================");
		disgest("MD2");
		disgest("MD4");
		disgest("MD5");
	}
	
	public static void sha() {
		log.info("=================Begin sha====================");
		disgest("SHA-1");
		disgest("SHA-224");
		disgest("SHA-256");
		disgest("SHA-384");
		disgest("SHA-512");
	}
	
	private static void macDisgest(String algorithm) {
		try {
			KeyGenerator macMd5 = KeyGenerator.getInstance(algorithm);
			// 产生密钥
			SecretKey secKey = macMd5.generateKey();
			Mac mac= Mac.getInstance(secKey.getAlgorithm());
			mac.init(secKey);
			byte [] digt = mac.doFinal(msgText.getBytes());
			log.info( "[" + algorithm + "]"+ new String(Hex.encodeHex(digt)));	
		} catch (NoSuchAlgorithmException | InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void mac() {
		log.info("=================Begin macMD5====================");
		macDisgest("HmacMD2");
		macDisgest("HmacMD4");
		macDisgest("HmacMD5");
		macDisgest("HmacSHA1");
		macDisgest("HmacSHA224");
		macDisgest("HmacSHA256");
		macDisgest("HmacSHA384");
		macDisgest("HmacSHA512");
	}
	
	public static void crc32() {
		log.info("=================Begin CRC32====================");
		CRC32 crc = new CRC32();
		crc.update(msgText.getBytes());
		log.info(Long.toHexString(crc.getValue()));
	}
	
	public static void des() {
		log.info("=================Begin DES====================");
		try {
			KeyGenerator kg = KeyGenerator.getInstance("DES");
			// 初始化秘钥的长度
			kg.init(56);
			// 随机产生一个密钥
			SecretKey sk = kg.generateKey();
			byte [] keyByte = sk.getEncoded();
			log.info("密钥:" + new String(Hex.encodeHex(keyByte)));
			
			// 生成DES的密钥
			DESKeySpec dks = new DESKeySpec(keyByte);
			SecretKeyFactory keyFact = SecretKeyFactory.getInstance("DES");
			SecretKey desKey = keyFact.generateSecret(dks);
			
			// 执行加密
			Cipher cipEncode = Cipher.getInstance("DES");
			cipEncode.init(Cipher.ENCRYPT_MODE, desKey);
			byte [] encodeByte = cipEncode.doFinal(msgText.getBytes());
			log.info("DES密文:" + new String(Hex.encodeHex(encodeByte)));
			
			// 直接解密
			Cipher cipDecode = Cipher.getInstance("DES");
			cipDecode.init(Cipher.DECRYPT_MODE, desKey);
			byte[] decodeByte = cipDecode.doFinal(encodeByte);
			log.info("DES明文:" + new String(decodeByte));
		} catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException e) {
			e.printStackTrace();
		}
	}
	
	public static void des3() {
		log.info("=================Begin 3DES====================");
		try {
			KeyGenerator kg = KeyGenerator.getInstance("DESede");
//			kg.init(new SecureRandom());
//			kg.init(168);
			kg.init(112);
			// 随机产生一个密钥
			SecretKey sk = kg.generateKey();
			byte [] keyByte = sk.getEncoded();
			log.info("3DES密钥:" + new String(Hex.encodeHex(keyByte)));
			
			// 生成DES的密钥
			DESKeySpec dks = new DESKeySpec(keyByte);
			SecretKeyFactory keyFact = SecretKeyFactory.getInstance("DES");
			SecretKey desKey = keyFact.generateSecret(dks);
			
			// 执行加密
			Cipher cipEncode = Cipher.getInstance("DES/ECB/PKCS5Padding");
			cipEncode.init(Cipher.ENCRYPT_MODE, desKey);
			byte [] encodeByte = cipEncode.doFinal(msgText.getBytes());
			log.info("3DES密文:" + new String(Hex.encodeHex(encodeByte)));
			
			// 直接解密
			Cipher cipDecode = Cipher.getInstance("DES/ECB/PKCS5Padding");
			cipDecode.init(Cipher.DECRYPT_MODE, desKey);
			byte[] decodeByte = cipDecode.doFinal(encodeByte);
			log.info("3DES明文:" + new String(decodeByte));
		} catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException e) {
			e.printStackTrace();
		}
	}	
	
	public static void aes() {
		log.info("=================Begin AES====================");
		try {
			KeyGenerator kg = KeyGenerator.getInstance("AES");
//			kg.init(new SecureRandom());
//			kg.init(256);
//			kg.init(192);
			kg.init(128);
			
			// 随机产生一个密钥
			SecretKey sk = kg.generateKey();
			byte [] keyByte = sk.getEncoded();
			log.info("AES密钥:" + new String(Hex.encodeHex(keyByte)));
			
			// 生成DES的密钥
			SecretKey desKey = new SecretKeySpec(keyByte, "AES");
			
			// 执行加密
			Cipher cipEncode = Cipher.getInstance("AES/ECB/PKCS5Padding");
			cipEncode.init(Cipher.ENCRYPT_MODE, desKey);
			byte [] encodeByte = cipEncode.doFinal(msgText.getBytes());
			log.info("AES密文:" + new String(Hex.encodeHex(encodeByte)));
			
			// 直接解密
			Cipher cipDecode = Cipher.getInstance("AES/ECB/PKCS5Padding");
			cipDecode.init(Cipher.DECRYPT_MODE, desKey);
			byte[] decodeByte = cipDecode.doFinal(encodeByte);
			log.info("AES明文:" + new String(decodeByte));
		} catch (NoSuchAlgorithmException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException e) {
			e.printStackTrace();
		}
	}
	
	public static void DH() {
		log.info("=================Begin DH====================");
		try {
			// 实例化密钥生成器			
			KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DH");
			// 初始密钥生成器
			keyPairGen.initialize(1024);
			// 生成甲方密钥对
			KeyPair keyP = keyPairGen.generateKeyPair();
			// 生成甲方公钥
			PublicKey aPubKey = keyP.getPublic();
			log.info(aPubKey.getFormat());
			log.info(new String(Hex.encodeHex(aPubKey.getEncoded())));
			// 生成甲方私钥
			PrivateKey aPriKey = keyP.getPrivate();
			log.info(aPriKey.getFormat());
			log.info(new String(Hex.encodeHex(aPriKey.getEncoded())));
			
			// 生成乙方私钥
			KeyFactory keyF = KeyFactory.getInstance("DH");			
			X509EncodedKeySpec x509keySpec = new X509EncodedKeySpec(aPubKey.getEncoded());
			DHParameterSpec dhParamSpec = ((DHPublicKey)aPubKey).getParams();
			KeyPairGenerator keyPairGenB = KeyPairGenerator.getInstance("DH");
			keyPairGenB.initialize(dhParamSpec);
			
			KeyPair keyPairB = keyPairGenB.generateKeyPair();
			PublicKey bPubKey = keyF.generatePublic(x509keySpec);
			PrivateKey bPriKey = keyPairB.getPrivate();

			// 生成甲方的本地密钥(甲的公钥 + 乙方的私钥)
			KeyAgreement keyAgreeA = KeyAgreement.getInstance(keyF.getAlgorithm());
			keyAgreeA.init(aPriKey);
			keyAgreeA.doPhase(bPubKey, true);
			SecretKey aLocalKeyA = keyAgreeA.generateSecret("AES");
			log.info("甲方的本地密钥:" + new String(Hex.encodeHex(aLocalKeyA.getEncoded())));
			
			// 生成乙方的本地密钥(乙方的私钥 + 甲方的公钥)
			KeyAgreement keyAgreeB = KeyAgreement.getInstance(keyF.getAlgorithm());
			keyAgreeB.init(bPriKey);
			keyAgreeB.doPhase(aPubKey, true);
			SecretKey aLocalKeyB = keyAgreeB.generateSecret("AES");
			log.info("乙方的本地密钥:" + new String(Hex.encodeHex(aLocalKeyB.getEncoded())));
			
			// 数据加密
			Cipher cipHerA = Cipher.getInstance("AES/ECB/PKCS5Padding");
			cipHerA.init(Cipher.ENCRYPT_MODE, aLocalKeyA);
			byte [] bDHByteA = cipHerA.doFinal(msgText.getBytes());
			log.info("甲方加密密文:" + new String(Hex.encodeHex(bDHByteA)));
			
			// 乙方明文
			Cipher cipHerB = Cipher.getInstance("AES/ECB/PKCS5Padding");
			cipHerB.init(Cipher.ENCRYPT_MODE, aLocalKeyB);
			byte [] bDHByteB = cipHerB.doFinal(msgText.getBytes());
			log.info("乙方解密明文:" + new String(Hex.encodeHex(bDHByteB)));
			
		} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
			e.printStackTrace();
		}
	}
	
	public static void RSA() {
		try {
			// 实例化密钥生成器		
			KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
			// 初始密钥生成器
			keyPairGen.initialize(1024);
			KeyPair keyP = keyPairGen.generateKeyPair();
			PublicKey aPubKey = keyP.getPublic();
			PrivateKey aPriKey = keyP.getPrivate();	
			log.info("公钥:" + new String(Hex.encodeHex(aPubKey.getEncoded())));
			log.info("私钥:" + new String(Hex.encodeHex(aPriKey.getEncoded())));
			
			// 公钥加密
			X509EncodedKeySpec x509SpecPub = new X509EncodedKeySpec(aPubKey.getEncoded());
			KeyFactory keyF = KeyFactory.getInstance("RSA");
			PublicKey pubKey = keyF.generatePublic(x509SpecPub);
			Cipher cipHerEncode = Cipher.getInstance(keyF.getAlgorithm());
			cipHerEncode.init(Cipher.ENCRYPT_MODE, pubKey);
			byte [] bRSAEncode = cipHerEncode.doFinal(msgText.getBytes());		
			log.info("加密密文:" + new String(Hex.encodeHex(bRSAEncode)));
			
			// 私钥解密
			PKCS8EncodedKeySpec pkcs8Pri = new PKCS8EncodedKeySpec(aPriKey.getEncoded());
			KeyFactory keyFDecode = KeyFactory.getInstance("RSA");
			PrivateKey priKey = keyFDecode.generatePrivate(pkcs8Pri);
			Cipher cipHerDecode = Cipher.getInstance(keyFDecode.getAlgorithm());
			cipHerDecode.init(Cipher.DECRYPT_MODE, priKey);
			byte [] bRSADecode = cipHerDecode.doFinal(bRSAEncode);
			log.info("解密明文:" + new String(bRSADecode));			
			
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BadPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void sign() {
		String msgText = "饶海军love world!";
//		// 产生密钥对
//		KeyPair keyP = RRSA.genKeyPair();
//		// 手动MD5 并 RSA一个签名
//		byte [] md5Byte = RMd5.encode(msgText.getBytes());
//		byte [] sigByOwnByte = RRSA.encodeByPrivateKey(keyP.getPrivate().getEncoded(), md5Byte);
//		// 加签
//		byte [] signByRSAByte = RSignature.signatureRSA(keyP.getPrivate(), msgText.getBytes());
//		log.info("MD5RSAOwn:" + new String(Hex.encodeHex(sigByOwnByte)));
//		log.info("MD5RSA:" + new String(Hex.encodeHex(signByRSAByte)));
//
//		// 验签
//		boolean bVerify = RSignature.verify(keyP.getPublic(), msgText.getBytes(), md5Byte);
//		log.info("验签结果:" + bVerify);
	}
	
	public static void test() {
//		base64();
//		// 摘要算法
//		md();
//		fileMd5();
//		sha();
//		mac();
//		crc32();
//		// 对称加密算法
//		des();
//		des3();
//		aes();
		// 非对称加密算法
		DH();
//		RSA();
//		sign();
	}
}
